use sea_orm::*;
use serde::Serialize;

pub trait QueryPageCondition<COL>
where
    COL: ColumnTrait,
{
    fn filter(&self) -> Condition;
    fn order_by(&self) -> Vec<(COL, Order)>;
}

#[derive(Debug, Serialize)]
pub struct QueryPageResp<'a, CONN, Q>
where
    CONN: ConnectionTrait,
    Q: QueryOrder + QueryFilter + PaginatorTrait<'a, CONN>,
    <<Q as sea_orm::PaginatorTrait<'a, CONN>>::Selector as sea_orm::SelectorTrait>::Item:
        std::fmt::Debug + Serialize,
{
    pub page_num: u64,
    pub page_size: u64,
    pub total: u64,
    pub items: Vec<<<Q as PaginatorTrait<'a, CONN>>::Selector as SelectorTrait>::Item>,
}

/**
 * 分页查询
 */
pub async fn query_page<'a, CONN, COND, COL, Q>(
    db: &'a CONN,
    mut select: Q,
    page_num: u64,
    page_size: u64,
    condition: &'a COND,
) -> anyhow::Result<QueryPageResp<'a, CONN, Q>>
where
    CONN: ConnectionTrait,
    COND: QueryPageCondition<COL>,
    COL: ColumnTrait,
    Q: QueryOrder + QueryFilter + PaginatorTrait<'a, CONN>,
    <<Q as sea_orm::PaginatorTrait<'a, CONN>>::Selector as sea_orm::SelectorTrait>::Item:
        std::fmt::Debug + Serialize,
{
    let filter = condition.filter();
    let order_by = condition.order_by();

    for (col, order) in order_by {
        select = select.order_by(col, order);
    }

    let query = select.filter(filter);

    let query = query.paginate(db, page_size);

    let total = query.num_items().await?;
    let items = query.fetch_page(page_num - 1).await?;

    let resp: QueryPageResp<'a, CONN, Q> = QueryPageResp {
        page_num,
        page_size,
        total,
        items,
    };

    Ok(resp)
}
